#include <X11/Xlib.h> 
#include <stdio.h>

#define NUM_OF_ELEMENTS(x) (sizeof (x) / sizeof *(x))

static int borderWidth = 4;
static int titleBarHeight = 23;
typedef struct Line {
	int x1;
	int x2;
	int y1;
	int y2;
	int initialized; 
} Line;

typedef struct Node {
	Window window;
	int initialized;
} Node;

void getAllLinesOnScreen(Window, Line[]);
void getListOfWindows(Node windowList[]);
void autoResize(Window window);

int main() {
	Display *display = XOpenDisplay(0);
	Node windowList[99];
	getListOfWindows(windowList);
	int i = 0;
	while(windowList[i].initialized == 1) {
		XSelectInput(display, windowList[i].window, KeyPressMask);
		i++;
	}
	XEvent e;
	while(1) {
		XNextEvent(display, &e);
		switch (e.type) {
			case KeyPress:
				printf ("The space bar was pressed.\n");
					autoResize(e.xkey.window);
			//	XMoveResizeWindow(display, e.xkey.window,
			//			0, 
			//			701, 
			//			683, 
			//			473);
				fflush(stdout);
				break;
			default:
				break;
		}
	}
	return 0;
}

void autoResize(Window window) {	
	Display *display = XOpenDisplay(0);
	/* translate from the parent window to the root window*/			 
	XWindowAttributes win_attr;
	XGetWindowAttributes(display, window, &win_attr);			
	int screen_x, screen_y;
	Window child_win;
	Window parent_win;
	Window root_win;
	Window* child_windows;
	unsigned int num_child_windows;
	XQueryTree(display, window,
			&root_win,
			&parent_win,
			&child_windows, &num_child_windows);
	XFree(child_windows);

	/* next, we make the coordinates translation, from the coordinates system 
	   of the parent window, to the coordinates system of the root window,    
	   which happens to be the same as that of the screen, since the root     
	   window always spans the entire screen size.                            
	   the 'x' and 'y' values are those previously returned by the            
	   XGetWindowAttributes function. */                                        
	XTranslateCoordinates(display, parent_win, root_win,
			win_attr.x, win_attr.y, &screen_x, &screen_y,
			&child_win);

	/*at this point, screen_x and screen_y contain the location of our original 
	  window, using screen coordinates. */

	/* build and store the 4 lines that are part of this window */

	int leftXPointWithBorders = screen_x;
	int upperYPointWithBorders = screen_y;
	int rightXPointWithBorders = leftXPointWithBorders + win_attr.width;
	int bottomYPointWithBorders = upperYPointWithBorders + win_attr.height;

	Line upperLine;	
	upperLine.x1 = leftXPointWithBorders;
	upperLine.x2 = rightXPointWithBorders;
	upperLine.y1 = upperYPointWithBorders;
	upperLine.y2 = upperYPointWithBorders; 

	Line lowerLine;
	lowerLine.x1 = leftXPointWithBorders;
	lowerLine.x2 = rightXPointWithBorders;
	lowerLine.y1 = bottomYPointWithBorders;
	lowerLine.y2 = bottomYPointWithBorders; 

	Line leftLine;
	leftLine.x1 = leftXPointWithBorders;
	leftLine.x2 = leftXPointWithBorders;
	leftLine.y1 = upperYPointWithBorders;//couldbe an error here not sure what y1 is
	leftLine.y2 = bottomYPointWithBorders; 

	Line rightLine;
	rightLine.x1 = rightXPointWithBorders;
	rightLine.x2 = rightXPointWithBorders;
	rightLine.y1 = upperYPointWithBorders;
	rightLine.y2 = bottomYPointWithBorders; 

	Line* allLinesOnScreen;	

	getAllLinesOnScreen(window, allLinesOnScreen);

	int top = scanUp(upperLine, allLinesOnScreen);
	int bottom = scanDown(lowerLine, allLinesOnScreen);
	int left = scanLeft(leftLine, allLinesOnScreen);
	int right = scanRight(rightLine, allLinesOnScreen);

	int y = top;
	int x = left;
	int height = bottom - top;
	int width = right - left;
		
	printf("y %i x %i height %i width %i", y, x, height, width); 
	fflush(stdout);
	XMoveResizeWindow(display, window, 
			x + borderWidth + 2, 
	       	        y + titleBarHeight + 2, 
	       	        width - 2 * borderWidth + 2, 
	       	        height - titleBarHeight - borderWidth + 2);
	XFlush(display);
}

void getAllLinesOnScreen(Window window, Line allLinesOnScreen[])
{
	Display *display = XOpenDisplay(0);
	Node windowList[99];
	getListOfWindows(windowList);

	int j = 0;
	int i = 0;
	int allLinesOnScreenCounter = 0;
	printf("\n");
	fflush(stdout);
	while(windowList[i].initialized == 1)
	{
		if(windowList[i].window != window) {
			char* window_name_return;
			printf("a%i", windowList[i].initialized);
			fflush(stdout);
			XFetchName(display, windowList[i].window, &window_name_return);
			XWindowAttributes win_attr;
			XGetWindowAttributes(display, windowList[i].window, &win_attr);
			printf(window_name_return);	
			printf("\n");
			fflush(stdout);
		}
		i++;
	}
			
	i = 0;
	while(windowList[i].initialized == 1)
	{
		if(windowList[i].window != window) {
			char* window_name_return;
			XFetchName(display, windowList[i].window, &window_name_return);
			printf("%i", windowList[i].initialized);
			printf(window_name_return);	
			printf("\n");
			fflush(stdout);
			
			// translate from the parent window to the root window			 
			XWindowAttributes win_attr;			
			XGetWindowAttributes(display, windowList[i].window, &win_attr);			
			/*int screen_x, screen_y;		                                                   
			Window child_win;			
			Window parent_win;                      
			Window root_win;			                                                       
			Window* child_windows;	
			unsigned int num_child_windows;	
			XQueryTree(display, windowList[i].window,
					&root_win,
					&parent_win,
					&child_windows, &num_child_windows);			                                         
			XFree(child_windows);

			// next, we make the coordinates translation, from the coordinates system 
			//   of the parent window, to the coordinates system of the root window,    
			//   which happens to be the same as that of the screen, since the root     
			//   window always spans the entire screen size.                            
			//   the 'x' and 'y' values are those previously returned by the            
			//   XGetWindowAttributes function.                                         
			XTranslateCoordinates(display, parent_win, root_win,
					win_attr.x, win_attr.y, &screen_x, &screen_y,
					&child_win);

			//at this point, screen_x and screen_y contain the location of our original 
			//  window, using screen coordinates. 

			// build and store the 4 lines that are part of this window 
			*/
			int leftXPointWithBorders = win_attr.x - borderWidth;
			int upperYPointWithBorders = win_attr.y - titleBarHeight;
			int rightXPointWithBorders = leftXPointWithBorders + win_attr.width + 2 * borderWidth;
			int bottomYPointWithBorders = upperYPointWithBorders + win_attr.height + titleBarHeight + borderWidth;

			Line leftXLineWithBorders;
			int x1 = leftXPointWithBorders;
			int y1 = upperYPointWithBorders;
			int x2 = leftXPointWithBorders;
			int y2 = bottomYPointWithBorders;
//			double a = y2 - y1;
//			double b = x1 - x2;
//			double c = (a * x1) + (b * y1);
			leftXLineWithBorders.x1 = x1;
			leftXLineWithBorders.y1 = y1;
			leftXLineWithBorders.x2 = x2;
			leftXLineWithBorders.y2 = y2;
//			leftXLineWithBorders.a = a;
//			leftXLineWithBorders.b = b;
//			leftXLineWithBorders.c = c;
			leftXLineWithBorders.initialized = 1;

			Line rightXLineWithBorders;
			x1 = rightXPointWithBorders;
			y1 = upperYPointWithBorders;
			x2 = rightXPointWithBorders;
			y2 = bottomYPointWithBorders;
//			a = y2 - y1;
//			b = x1 - x2;
//			c = (a * x1) + (b * y1);
			rightXLineWithBorders.x1 = x1;
			rightXLineWithBorders.y1 = y1;
			rightXLineWithBorders.x2 = x2;
			rightXLineWithBorders.y2 = y2;
//			rightXLineWithBorders.a = a;
//			rightXLineWithBorders.b = b;
//			rightXLineWithBorders.c = c;    
			rightXLineWithBorders.initialized = 1;

			Line upperYLineWithBorders;
			x1 = leftXPointWithBorders;
			y1 = upperYPointWithBorders;
			x2 = rightXPointWithBorders;
			y2 = upperYPointWithBorders;
//			a = y2 - y1;
//			b = x1 - x2;
//			c = (a * x1) + (b * y1);
			upperYLineWithBorders.x1 = x1;
			upperYLineWithBorders.y1 = y1;
			upperYLineWithBorders.x2 = x2;
			upperYLineWithBorders.y2 = y2;
//			upperYLineWithBorders.a = a;
//			upperYLineWithBorders.b = b;
//			upperYLineWithBorders.c = c;
			upperYLineWithBorders.initialized = 1;


			Line bottomYLineWithBorders;
			x1 = leftXPointWithBorders;
			y1 = bottomYPointWithBorders;
			x2 = rightXPointWithBorders;
			y2 = bottomYPointWithBorders;
//			a = y2 - y1;
//			b = x1 - x2;
//			c = (a * x1) + (b * y1);
			bottomYLineWithBorders.x1 = x1;
			bottomYLineWithBorders.y1 = y1;
			bottomYLineWithBorders.x2 = x2;
			bottomYLineWithBorders.y2 = y2;
//			bottomYLineWithBorders.a = a;
//			bottomYLineWithBorders.b = b;
//			bottomYLineWithBorders.c = c;
			bottomYLineWithBorders.initialized = 1;


			allLinesOnScreen[allLinesOnScreenCounter] = leftXLineWithBorders;
			allLinesOnScreenCounter++;
			allLinesOnScreen[allLinesOnScreenCounter] = rightXLineWithBorders;
			allLinesOnScreenCounter++;
			allLinesOnScreen[allLinesOnScreenCounter] = upperYLineWithBorders;
			allLinesOnScreenCounter++;
			allLinesOnScreen[allLinesOnScreenCounter] = bottomYLineWithBorders;
			allLinesOnScreenCounter++;
		}
		i++;
		j+=2;
	}
	/* now add the desktop to the grid of lines*/
	XWindowAttributes win_attr;			
	XGetWindowAttributes(display, DefaultRootWindow(display), &win_attr);
	int leftXPoint = win_attr.x;
	int upperYPoint = win_attr.y;
	int rightXPoint = leftXPoint + win_attr.width;
	int bottomYPoint = upperYPoint + win_attr.height;

	/*xLines are lines that are perpendicular to the bottom of the desktop*/
	Line leftXLine;
	int x1 = leftXPoint;
	int y1 = upperYPoint;
	int x2 = leftXPoint;
	int y2 = bottomYPoint;
//	double a = y2 - y1;
//	double b = x1 - x2;
//	double c = (a * x1) + (b * y1);
	leftXLine.x1 = x1;
	leftXLine.y1 = y1;
	leftXLine.x2 = x2;
	leftXLine.y2 = y2;
//	leftXLine.a = a;
//	leftXLine.b = b;
//	leftXLine.c = c;
	leftXLine.initialized = 1;

	Line rightXLine;
	x1 = rightXPoint;
	y1 = upperYPoint;
	x2 = rightXPoint;
	y2 = bottomYPoint;
//	a = y2 - y1;
//	b = x1 - x2;
//	c = (a * x1) + (b * y1);
	rightXLine.x1 = x1;
	rightXLine.y1 = y1;
	rightXLine.x2 = x2;
	rightXLine.y2 = y2;
//	rightXLine.a = a;
//	rightXLine.b = b;
//	rightXLine.c = c;
	rightXLine.initialized = 1;


	/* yLines are lines that are parallel to the bottom of the desktop*/
	Line upperYLine;
	x1 = leftXPoint;
	y1 = upperYPoint;
	x2 = rightXPoint;
	y2 = upperYPoint;
//	a = y2 - y1;
//	b = x1 - x2;
//	c = (a * x1) + (b * y1);
	upperYLine.x1 = x1;
	upperYLine.y1 = y1;
	upperYLine.x2 = x2;
	upperYLine.y2 = y2;
//	upperYLine.a = a;
//	upperYLine.b = b;
//	upperYLine.c = c;
	upperYLine.initialized = 1;

	Line bottomYLine;
	x1 = leftXPoint;
	y1 = bottomYPoint;
	x2 = rightXPoint;
	y2 = bottomYPoint;
//	a = y2 - y1;
//	b = x1 - x2;
//	c = (a * x1) + (b * y1);
	bottomYLine.x1 = x1;
	bottomYLine.y1 = y1;
	bottomYLine.x2 = x2;
	bottomYLine.y2 = y2;
//	bottomYLine.a = a;
//	bottomYLine.b = b;
//	bottomYLine.c = c;
	bottomYLine.initialized = 1;

	allLinesOnScreen[allLinesOnScreenCounter] = leftXLine;
	allLinesOnScreenCounter++;
	allLinesOnScreen[allLinesOnScreenCounter] = rightXLine;
	allLinesOnScreenCounter++;
	allLinesOnScreen[allLinesOnScreenCounter] = upperYLine;
	allLinesOnScreenCounter++;
	allLinesOnScreen[allLinesOnScreenCounter] = bottomYLine;


	/*allLinesOnScreen.push_back(leftXLine);
	  allLinesOnScreen.push_back(rightXLine);	
	  allLinesOnScreen.push_back(upperYLine);
	  allLinesOnScreen.push_back(bottomYLine);*/
}

void getListOfWindows(Node windowList[])
{
	int i;
	for(i = 0; i < 99; i++)
	{
		windowList[i].initialized = 0;
	}

	Display *display = XOpenDisplay(0);
	Atom actual_type;
	int actual_format;
	unsigned long nitems, bytes_after;
	unsigned char *prop;
	XGetWindowProperty(display, DefaultRootWindow(display),
			XInternAtom(display, "_NET_CLIENT_LIST", 1),
			0L, 100000, 0, AnyPropertyType, &actual_type,
			&actual_format, &nitems, &bytes_after, &prop);
	Window* list;
	list = (Window*) prop;
	int windowListCount = 0;
	for (i = 0; i < nitems; i++)
	{

		Atom windowType = None;
		Atom actual_type;
		int actual_format;
		unsigned long nitems, bytes_after;
		unsigned char *prop_return = NULL;

		if(Success == XGetWindowProperty(display, list[i],
					XInternAtom(display, "_NET_WM_WINDOW_TYPE", False),
					0L, sizeof(Atom),
					False, AnyPropertyType, &actual_type,
					&actual_format, &nitems, &bytes_after,
					&prop_return) && prop_return)
		{
			windowType = *(Atom *)prop_return;
			XFree(prop_return);
		}

		char* window_name_return;
		XFetchName(display, list[i], &window_name_return);
		if(windowType == XInternAtom(display, "_NET_WM_WINDOW_TYPE_NORMAL", 0))
       		{
        		//string name = new string(window_name_return);
        	        //	if(window_name_return[0] != 'c')       	
        		//	{  
			printf(window_name_return);
			printf("\n");
			fflush(stdout);
			windowList[windowListCount].window = list[i];
      			windowList[windowListCount].initialized = 1;
             	 	windowListCount++;
	 	}
	}
}

int scanUp(Line line, Line allLinesOnScreen[])
{	
	Line closestLine;
	int firstLineFound = 0;
	int i = 0;
	while(allLinesOnScreen[i].initialized)
	{
		if(firstLineFound == 0)		
		{
			// if horozontal
			if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2)
			{
				// if the line is above the start point of the line were scaning up
				if(allLinesOnScreen[i].y1 <= line.y1)
				{					
					// if the line blocks the path of the line we are scanning up
					// ie if anypart of the line line overlaps with anypart of the line we are scanning up									
					if(allLinesOnScreen[i].x2 > line.x1 && allLinesOnScreen[i].x1 < line.x2)
					{
						// this could be one line that we want
						closestLine = allLinesOnScreen[i];
						firstLineFound = 1;
					}								
				}
			}
		}
		else if(firstLineFound == 1)		
		{
			// if horozontal
			if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2)
			{
				// if the line is above the start point
				if(allLinesOnScreen[i].y1 <= line.y1)
				{
					// if the line blocks the path of the line we are scanning up
					// ie if anypart of the line line overlaps with anypart of the line we are scanning up	
					if(allLinesOnScreen[i].x2 > line.x1 && allLinesOnScreen[i].x1 < line.x2)
					{		
						// if this line is closer to the point that got hit 
						// than one we allready found
						if(allLinesOnScreen[i].y1 > closestLine.y1)
						{					
							// this could be one line that we want
							closestLine = allLinesOnScreen[i];								
						}																
					}
				}
			}
		}
		i++;		
	}
	return closestLine.y1;
}

int scanDown(Line line, Line allLinesOnScreen[])
{		
	Line closestLine;
	int firstLineFound = 0;
	int i = 0;
	while(allLinesOnScreen[i].initialized)
	{
		if(firstLineFound == 0)		
		{
			// if horozontal
			if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2)
			{
				// if the line is below the start point
				if(allLinesOnScreen[i].y1 >= line.y1)
				{					
					// if the line blocks the path of the line we are scanning down
					// ie if anypart of the line line overlaps with anypart of the line we are scanning down									
					if(allLinesOnScreen[i].x2 > line.x1 && allLinesOnScreen[i].x1 < line.x2)
					{
						// this could be one line that we want
						closestLine = allLinesOnScreen[i];
						firstLineFound = 1;
					}								
				}
			}
		}
		else if(firstLineFound == 1)		
		{
			// if horozontal
			if(allLinesOnScreen[i].y1 == allLinesOnScreen[i].y2)
			{
				// if the line is below the start point
				if(allLinesOnScreen[i].y1 >= line.y1)
				{
					// if the line blocks the path of the line we are scanning down
					// ie if anypart of the line line overlaps with anypart of the line we are scanning up	
					if(allLinesOnScreen[i].x2 > line.x1 && allLinesOnScreen[i].x1 < line.x2)
					{		
						// if this line is closer to the point that got hit 
						// than one we allready found
						if(allLinesOnScreen[i].y1 < closestLine.y1)
						{					
							// this could be one line that we want
							closestLine = allLinesOnScreen[i];								
						}																
					}
				}
			}
		}
		i++;		
	}
	return closestLine.y1;
}

int scanLeft(Line line, Line allLinesOnScreen[])
{	
	Line closestLine;
	int firstLineFound = 0;
	int i = 0;
	while(allLinesOnScreen[i].initialized)
	{
		if(firstLineFound == 0)		
		{
			// if vertical
			if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2)
			{
				// if the line is Left of the start point
				if(allLinesOnScreen[i].x1 <= line.x1)
				{					
					// if the line blocks the path of the line we are scanning Left
					// ie if anypart of the line line overlaps with anypart of the line we are scanning up									
					if(allLinesOnScreen[i].y2 > line.y1 && allLinesOnScreen[i].y1 < line.y2)
					{
						// this could be one line that we want
						closestLine = allLinesOnScreen[i];
						firstLineFound = 1;
					}								
				}
			}
		}
		else if(firstLineFound == 1)		
		{
			// if vertical
			if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2)
			{
				// if the line is left the start point
				if(allLinesOnScreen[i].x1 <= line.x1)
				{
					// if the line blocks the path of the line we are scanning left
					// ie if anypart of the line line overlaps with anypart of the line we are scanning up	
					if(allLinesOnScreen[i].y2 > line.y1 && allLinesOnScreen[i].y1 < line.y2)
					{		
						// if this line is closer to the point that got hit 
						// than one we allready found
						if(allLinesOnScreen[i].x1 > closestLine.x1)
						{					
							// this could be one line that we want
							closestLine = allLinesOnScreen[i];								
						}																
					}
				}
			}
		}
		i++;	
	}
	return closestLine.x1;
}

int scanRight(Line line, Line allLinesOnScreen[])
{	
	Line closestLine;
	int firstLineFound = 0;
	int i = 0;
	while(allLinesOnScreen[i].initialized)
	{
		if(firstLineFound == 0)		
		{
			// if vertical
			if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2)
			{
				// if the line is Right of the start point
				if(allLinesOnScreen[i].x1 >= line.x1)
				{					
					// if the line blocks the path of the line we are scanning Right
					// ie if anypart of the line line overlaps with anypart of the line we are scanning up									
					if(allLinesOnScreen[i].y2 > line.y1 && allLinesOnScreen[i].y1 < line.y2)
					{
						// this could be one line that we want
						closestLine = allLinesOnScreen[i];
						firstLineFound = 1;
					}								
				}
			}
		}
		else if(firstLineFound == 1)		
		{
			// if vertical
			if(allLinesOnScreen[i].x1 == allLinesOnScreen[i].x2)
			{
				// if the line is Right the start point
				if(allLinesOnScreen[i].x1 >= line.x1)
				{
					// if the line blocks the path of the line we are scanning Right
					// ie if anypart of the line line overlaps with anypart of the line we are scanning up	

					// get all the lines on screen
					if(allLinesOnScreen[i].y2 > line.y1 && allLinesOnScreen[i].y1 < line.y2)
					{		
						// if this line is closer to the point that got hit 
						// than one we allready found
						if(allLinesOnScreen[i].x1 < closestLine.x1)
						{					
							// this could be one line that we want
							closestLine = allLinesOnScreen[i];								
						}																
					}
				}
			}
		}
		i++;		
	}
	return closestLine.x1;
}
